﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace TCHostUse.Toolkit
{
    public class EmbeddedExeTool
    {
        [DllImport("User32.dll", EntryPoint = "SetParent")]
        private static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);

        [DllImport("user32.dll", EntryPoint = "ShowWindow")]
        private static extern int ShowWindow(IntPtr hwnd, int nCmdShow);

        [DllImport("user32.dll", SetLastError = true)]
        private static extern bool MoveWindow(IntPtr hwnd, int x, int y, int cx, int cy, bool repaint);
        //[DllImport("user32.dll")]
        //private static extern int GetWindowLong(IntPtr hWnd, int nIndex);
        //[DllImport("user32.dll")]
        //private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
        //[DllImport("user32.dll", SetLastError = true)]
        //private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
        IntPtr WindowHandle = IntPtr.Zero;
        private const int WS_THICKFRAME = 262144;
        private const int WS_BORDER = 8388608;
        private const int GWL_STYLE = -16;//也可以是-16
        private const int WS_MAXIMIZEBOX = 0x00010000; // 窗口有最大化按钮
        private const int WS_MINIMIZEBOX = 0x00020000; // 窗口有最小化按钮
        private const int WS_CAPTION = 0xC00000;
        private Process proApp = null;//进程名称
        private Control ContainerControl = null;//控件名称
        private const int WS_VISIBLE = 0x10000000;
        [DllImport("user32.dll", EntryPoint = "SetWindowLong", CharSet = CharSet.Auto)]
        private static extern IntPtr SetWindowLongPtr32(HandleRef hWnd, int nIndex, int dwNewLong);
        [DllImport("user32.dll", EntryPoint = "SetWindowLongPtr", CharSet = CharSet.Auto)]
        private static extern IntPtr SetWindowLongPtr64(HandleRef hWnd, int nIndex, int dwNewLong);
        [DllImport("user32.dll", EntryPoint = "GetWindowLong")]
        public static extern int GetWindowLong(IntPtr hwnd, int nIndex);

        private IntPtr SetWindowLong(HandleRef hWnd, int nIndex, int dwNewLong)
        {
            if (IntPtr.Size == 4)//32位程序
            {
                return SetWindowLongPtr32(hWnd, nIndex, dwNewLong);
            }
            else//64位程序
            {
                return SetWindowLongPtr64(hWnd, nIndex, dwNewLong);
            }
        }

        /// <summary>
        /// 加载外部exe程序到程序容器中
        /// </summary>
        /// <param name="control">exe容器控件</param>
        /// <param name="exepath">exe绝对路径</param>
        public void LoadEXE(Control control, string exepath)
        {
            if (this.proApp == null || this.proApp.HasExited)//如果进程为空或进程已关闭
            {
                ContainerControl = control;
                control.SizeChanged += Control_SizeChanged;
                //进程启动信息
                ProcessStartInfo info = new ProcessStartInfo(exepath);
                info.WindowStyle = ProcessWindowStyle.Normal;
                info.UseShellExecute = false;
                info.CreateNoWindow = false;
                //启动进程
                proApp = Process.Start(info);
                Application.Idle += Application_Idle;//添加事件，即当应用程序处理完成进入空闲状态时触发的事件
                EmbedProcess(proApp, control);
            }
        }

        /// <summary>
        /// 确保应用程序嵌入此容器
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Application_Idle(object sender, EventArgs e)
        {
            if (this.proApp == null || this.proApp.HasExited)//如果进程为空或进程已退出
            {
                this.proApp = null;
                Application.Idle -= Application_Idle;//移除事件，即当应用程序处理完成进入空闲状态时触发的事件
                return;
            }
            if (proApp.MainWindowHandle == IntPtr.Zero)
            {
                return;
            }
            Application.Idle -= Application_Idle;
            EmbedProcess(proApp, ContainerControl);
        }

        /// <summary>
        /// 将指定的程序嵌入控件中
        /// </summary>
        /// <param name="app">进程名称</param>
        /// <param name="control">控件名称</param>
        private void EmbedProcess(Process app, Control control)
        {
            if (app == null || app.MainWindowHandle == IntPtr.Zero || control == null)
            {
                return;
            }
            try
            {
                int nStyle = GetWindowLong(app.MainWindowHandle, GWL_STYLE);
                nStyle &= ~WS_MINIMIZEBOX;
                SetParent(app.MainWindowHandle, control.Handle); //设置父窗体
                SetWindowLong(new HandleRef(this, app.MainWindowHandle), (GWL_STYLE), nStyle);//去除边框
                ShowWindow(app.MainWindowHandle, (int)ProcessWindowStyle.Maximized);//显示窗体
                
                MoveWindow(app.MainWindowHandle, 0, 0, control.Width, control.Height, true);//移动窗体
            }
            catch (Exception ex3)
            {
                MessageBox.Show((ex3.Message));
            }
        }
        /// <summary>
        /// 嵌入容器大小改变事件
        /// </summary>
        private void Control_SizeChanged(object sender, EventArgs e)
        {
            if (proApp == null)
            {
                return;
            }
            if (proApp.MainWindowHandle != IntPtr.Zero && ContainerControl != null)
            {
                MoveWindow(proApp.MainWindowHandle, 0, 0, ContainerControl.Width, ContainerControl.Height, true);
            }
        }
    }
}
